"""
https://github.com/gitlabhq/gitlabhq/blob/master/doc/api/README.md
"""

import urllib, urllib2, cookielib

__all__=[
  "ApiClassBase",
  "ApiMethodCollectionBase",
  "InvalidArgumentsException",
  "ApiException"
]

class InvalidArgumentsException(Exception):
  pass

class ApiException(Exception):
  pass

class ApiClassBase(object):
  def __init__(self, host, port, email=None, password=None, schema="http"):
    self.host = host
    self.port = port
    self.email = email
    self.password = password
    self.schema = schema.lower()
    self.api_base = "%s://%s"%(
      self.schema,
      self.host,
    )
    if self.schema=="http" and port==80:
      pass
    elif self.schema=="https" and port==443:
      pass
    else:
      self.api_base+=":%s"%self.port
    self.opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookielib.CookieJar()))

  def _do_GET(self, url, params={}, headers={}):
    query = urllib.urlencode(params)
    data = None
    code = -1
    try:
      #print url+"?"+query
      req = urllib2.Request(url+"?"+query, headers=headers)
      res = self.opener.open(req)
      data = res.read()
      code = res.code
      res.close()
    except urllib2.HTTPError, e:
      code = e.code
      if e.code/100 == 2:
        data = e.read()
    return (code,data)

  def _do_DELETE(self, url, params={}, headers={}):
    query = urllib.urlencode(params)
    data = None
    code = -1
    try:
      #print url+"?"+query
      req = urllib2.Request(url+"?"+query, headers=headers)
      req.get_method = lambda: 'DELETE'
      res = self.opener.open(req)
      data = res.read()
      code = res.code
      res.close()
    except urllib2.HTTPError, e:
      code = e.code
      if e.code/100 == 2:
        data = e.read()
    return (code,data)
      
  def _do_POST(self, url, params={}, headers={}):
    postdata = urllib.urlencode(params)
    data = None
    code = -1
    try:
      #print url+":"+postdata
      req = urllib2.Request(url, data=postdata, headers=headers)
      res = self.opener.open(req)
      data = res.read()
      code = res.code
      res.close()
    except urllib2.HTTPError, e:
      code = e.code
      if e.code/100 == 2:
        data = e.read()
    return (code,data)

  def _do_PUT(self, url, params={}, headers={}):
    putdata = urllib.urlencode(params)
    data = None
    code = -1
    try:
      #print url+" | "+putdata
      req = urllib2.Request(url, data=putdata, headers=headers)
      req.get_method = lambda: 'PUT'
      res = self.opener.open(req)
      data = res.read()
      code = res.code
      res.close()
    except urllib2.HTTPError, e:
      code = e.code
      if e.code/100 == 2:
        data = e.read()
    return (code,data)
      

class ApiMethodCollectionBase(object):
  @classmethod
  def _validate_arguments(cls, *args, **kwargs):
    found_ApiClassBase = False
    for arg in args:
      if isinstance(arg, ApiClassBase):
        found_ApiClassBase = True
    if not found_ApiClassBase:
      raise InvalidArgumentsException("ApiClass is not found in argument(s)")

  @classmethod
  def _validate_arguments_not_None(cls, *args, **kwargs):
    for arg in args:
      if arg is None:
        raise InvalidArgumentsException("Argument(s) contains None.")
    for k,v in kwargs.items():
      if v is None:
        raise InvalidArgumentsException("%s must not be None."%k)
